/* Copyrights Security Engineering Research Group 
 * Author: Nauman (http://recluze.wordpress.com) 
 * 
 */

package edu.serg.mbar.ucon;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import org.apache.log4j.Logger;

import edu.serg.mbar.ucon.interfaces.DecisionEvent;
import edu.serg.mbar.ucon.interfaces.IsUCONCompatible;
import edu.serg.mbar.ucon.meta.*;
import edu.serg.mbar.ucon.pdp.AccessManager;
import edu.serg.mbar.ucon.interfaces.*;

/**
 * This class is responsible for maintaining the context of the UCON usage
 * session. It maintains a Map of Subject ID (key) against {@link SubjectInfo}.
 * This allows for storing the subject attributes, objects accessible to the
 * subject and the corresponding rights. This information is stored in various
 * structures within the class.
 * 
 * This class is responsible for UCON decision enforcement. The decisions are
 * received from the {@link AccessManager} through events.
 * 
 * @see ObjectInstance
 * @see SubjectInfo
 * @see AttributeCollection
 * @see AccessManager
 * 
 * 
 * @author Nauman (recluze.wordpress.com)
 * 
 */
public class ContextManager extends Thread implements IsUCONCompatible {
	/* The log for this class */
	private static Logger log = Logger.getLogger(ContextManager.class);;

	/** The key name of the subject's unique ID */
	private final static String UNIQUE_ID_KEY = RegisteredStrings.UNIQUE_ID_KEY;

	/** The Map for storing the subjects information */
	private Map<String, SubjectInfo> subjects;

	/** The Access Control Matrix for (s,o,r) */
	private Map<String, Map<String, Map<String, UsageSession>>> accessControlMatrix;

	/**
	 * The default constructor. It is the responsibility of the calling object
	 * to register this ContextManager as the event handler for the
	 * AccessManager.
	 */
	public ContextManager() {
		subjects = new HashMap<String, SubjectInfo>();
		accessControlMatrix = new HashMap<String, Map<String, Map<String, UsageSession>>>();
	}

	/**
	 * 
	 * this method creates a new usage session for the set of subject, object,
	 * right. the usage session
	 * 
	 * @param subjectID
	 * @param objectID
	 * @param right
	 */
	public void createNewUsageSession(String subjectID, String objectID,
			String right) {

	}

	/**
	 * Add a subject for management. The passed map must contain subject
	 * attributes. There must be at least one attribute called "mbar:Subject_ID"
	 * which corresponds to the unique subject name. There MUST be only one
	 * value of this attribute.
	 * 
	 * @param subjectAttributes
	 *            Attributes of the subject
	 */
	public void addSubject(String subject_ID)
			throws InvalidSubjectInfoException {
		log
				.info("Received a request to register a new subject. Retrieving attribute information.");

		// String subject_ID;
		/*
		 * subject_ID = subjectAttributes.get(UNIQUE_ID_KEY).firstElement(); if
		 * (subject_ID == null || subject_ID == "") throw new
		 * InvalidSubjectInfoException();
		 * 
		 * log.info("Retrieved subject unique ID: " + subject_ID);
		 */
		log.debug("Adding subject information.");
		log.debug("Creating a new SubjectInfo object");
		SubjectInfo subjectInformation = new SubjectInfo();
		// Vector<String> vals = new Vector<String>();
		// AttributeCollection attribCollection = new AttributeCollection();

		// for (String s : subjectAttributes.keySet()) {
		// log.info("Adding subject attribute: " + s);
		// // TODO: This doesn't look right. Why are we reading only the first
		// // element? Because we have only one mbar:UNIQUE_ID.
		// vals.add(subjectAttributes.get(s).firstElement());
		// //attribCollection.addAttribute(s, vals);
		// }

		// subjectInformation.getAttributes().add(attribCollection);

		log.debug("Adding subject info to the registered subjects list");
		subjects.put(subject_ID, subjectInformation);

		log.debug("Currently " + subjects.size() + " subjects are registered.");

	}

	public Set<String> getSubjectSet() {
		return subjects.keySet();
	}

	/**
	 * Request the use of an Object.
	 * 
	 * @param subjectID
	 * @param objectID
	 * @param preUpdate
	 * @return Initial decision to allow/deny
	 */
	public boolean requestObject(String subjectID, String objectID, String right) {
		// TODO: add a parameter of type IsUCONCompatible
		log.info("Received a usage request (" + subjectID + " , " + objectID
				+ " , " + right + ")");

		return false;
	}

	/**
	 * Process a continuous decision generated by the {@link AccessManager}
	 * 
	 * @param e
	 *            DecisionEvent generated by the {@link AccessManager}
	 */
	public void processContinuityDecision(DecisionEvent e) {
		log.info("Received AccessDecision of type: " + e.decisionType);
	}
}
